package qe.spider;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReadConfig;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import lombok.extern.slf4j.Slf4j;
import qe.spider.cfg.Factor;
import qe.spider.cfg.Others;
import qe.spider.cfg.PlateConfig;
import qe.spider.grab.*;
import qe.spider.tools.FeiShuNotice;
import qe.spider.tools.SyncFactor;
import qe.spider.tools.WSNotice;
import qe.spider.trade.SendBuySignal;
import qe.spider.trade.TradeAnalyser;
import qe.spider.trade.huaxin.StockTradeHuaXin;
import qe.spider.trade.ths_lanzi.StockTradeTHSLanZi;
import qe.spider.vo.*;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
import static cn.hutool.core.date.DatePattern.NORM_TIME_FORMATTER;
import static qe.spider.trade.SendBuySignal.BaseTradePath;

@Slf4j
public class MainSelect {
    public static Factor factor;
    public static StockTradeTHSLanZi ths_01 = new StockTradeTHSLanZi("95181294");

    public static void main(String[] args) throws IOException {
        String userId = "111775r";
        String token = "13f1764f728c8db11f85b98e524bec3c";
        MainSelect main = new MainSelect(userId, token);
        new WSNotice(new ArrayList<>(), false).recovery().forEach(gs -> goods.put(gs.getCode(), gs));
        CronUtil.schedule("*/5 * 9-12,13-16 * * 1-5", new Task() {
            @Override
            public void execute() {
                try {
                    factor = new SyncFactor().get();
                    log.info("开始新一轮选股----因子：{}", factor);
                    StockTradeHuaXin.initHuaXinTrade();
                    StockTradeTHSLanZi.initTHSTrade();
                    Collection<Plate> topPlate = main.getTopPlate();
                    List<Stock> stocks = main.selectStock(topPlate);
                    Boolean hasNew = main.upStock(stocks);
                    List<GoodStock> goodStocks = goods.values().stream().sorted(Comparator.comparing(GoodStock::getUpTime)).collect(Collectors.toList());
                    new WSNotice(goodStocks, hasNew).send();
                    if (System.getProperty("wsn_port", "8888").equals("80")) {
                        if (hasNew && !goodStocks.isEmpty()) new FeiShuNotice(goodStocks).send();
                    }
                    if (DateUtil.now().substring(11, 16).compareTo("15:01") >= 0) saveGoods(goodStocks);//收盘时保存榜单和收盘涨幅
                } catch (IOException e) {
                    log.error("出错了----" + e.getMessage(), e);
                }
            }
        });
        // 支持秒级别定时任务
        CronUtil.setMatchSecond(true);
        CronUtil.start();
        main.keepAlive();
    }

    private static Map<String, GoodStock> goods = new ConcurrentHashMap<String, GoodStock>();
    private static Map<String, Stock> all_stocks = new ConcurrentHashMap<String, Stock>();
    private static Map<String, Plate> all_plates = new ConcurrentHashMap<String, Plate>();

    public static Plate updatePlate(Plate np) {
        if (null == np) return null;
        if (!all_plates.containsKey(np.getName())) all_plates.put(np.getName(), np);
        Plate op = all_plates.get(np.getName());
        return op == null ? null : all_plates.put(np.getName(), op.update(np));
    }

    public static Stock updateStock(Stock ns) {
        if (null == ns) return null;
        if (!all_stocks.containsKey(ns.getStock_code())) all_stocks.put(ns.getStock_code(), ns);
        Stock os = all_stocks.get(ns.getStock_code());
        return os == null ? null : all_stocks.put(ns.getStock_code(), os.merge(ns));
    }

    private String userID;
    private String token;

    public MainSelect(String userID, String token) {
        this.userID = userID;
        this.token = token;
    }

    public Collection<Plate> getTopPlate() throws IOException {
        log.info("抓取上榜板块...");
        Collection<Plate> top = new ArrayList<>();
        try {
            if (!factor.getOnlyUseTHS()) {
                PlateList jingxuan = new GrabKPLJingXuanPlate(this.userID, this.token).grab();
                PlateList gainian = new GrabKPLGaiNianPlate(this.userID, this.token).grab();
                PlateList hangye = new GrabKPLHangYePlate(this.userID, this.token).grab();
                if (!jingxuan.getPlates().getPlates().isEmpty() || !gainian.getPlates().getPlates().isEmpty() || !hangye.getPlates().getPlates().isEmpty()) {
                    Set<Plate> njx = jingxuan.getPlates().getPlates().stream().map(MainSelect::updatePlate).filter(Objects::nonNull).collect(Collectors.toSet());
                    Set<Plate> ngn = gainian.getPlates().getPlates().stream().map(MainSelect::updatePlate).filter(Objects::nonNull).collect(Collectors.toSet());
                    Set<Plate> nhy = hangye.getPlates().getPlates().stream().map(MainSelect::updatePlate).filter(Objects::nonNull).collect(Collectors.toSet());
                    top = PlateList.mergeKPLPlates(njx, ngn, nhy);
                    if (log.isDebugEnabled())
                        log.debug("是否只用同花顺={}，抓取的开盘啦的板块精选：{}  ； 概念：{}  ； 板块行业：{}  ： 上榜板块：{} ", factor.getOnlyUseTHS(),
                                njx.stream().map(Plate::getName).collect(Collectors.joining(",")),
                                ngn.stream().map(Plate::getName).collect(Collectors.joining(",")),
                                nhy.stream().map(Plate::getName).collect(Collectors.joining(",")),
                                top.stream().map(Plate::getName).collect(Collectors.joining(",")));
                }
            }
        } catch (IOException e) {
            log.error("抓取开盘啦概念和行业板块出错，使用同花顺板块数据", e);
        }
        Collection<Plate> thsPlate = parseTHSPlate();
        if (log.isDebugEnabled())
            log.debug("抓取的同花顺的上榜板块：{}", thsPlate.stream().map(Plate::getName).collect(Collectors.joining(",")));
        top = Stream.concat(top.stream(), thsPlate.stream()).collect(Collectors.toSet());
        Collection<String> topPlateNames = top.stream().map(Plate::upTop).map(Plate::getName).collect(Collectors.toSet());//板块标记为上榜
        log.info("合并后的【上榜板块】：{}", String.join(", ", topPlateNames));
        all_plates.putAll(top.stream().collect(Collectors.toConcurrentMap(Plate::getName, each -> each, (value1, value2) -> value1)));//新板块放入map
        all_plates.values().stream().filter(p -> !topPlateNames.contains(p.getName())).forEach(Plate::downTop);//其他板块下榜
        return top;
    }

    private Collection<Plate> parseTHSPlate() throws IOException {
        Plates plates = new Plates();
        plates.setGrabTime(new Date());
        plates.parseThs();
        if (plates.getPlates().isEmpty()) return plates.getPlates();
        PlateList plateList = new PlateList();
        plateList.setPlates(plates);
        List<String> exculedPlateNames = Optional.ofNullable(factor.getOthers()).map(Others::getPlateConfig).map(PlateConfig::getExcludesTHSGaiNian).orElse(new ArrayList<>());
        Set<Plate> jingxuan = new HashSet<>();
        Set<Plate> gainian = plates.getPlates().stream().filter(Objects::nonNull).filter(p -> "概念".equals(p.getCategory()) && !exculedPlateNames.contains(p.getName())).map(MainSelect::updatePlate).filter(Objects::nonNull).collect(Collectors.toSet());
        Set<Plate> hangye = plates.getPlates().stream().filter(Objects::nonNull).filter(p -> "行业".equals(p.getCategory())).map(MainSelect::updatePlate).filter(Objects::nonNull).collect(Collectors.toSet());
//        return PlateList.mergePlates(jingxuan, gainian, hangye);
        return PlateList.mergeTHSPlates(gainian, hangye);
    }

    public List<Stock> selectStock(Collection<Plate> topPlate) throws IOException {
        log.info("抓取个股...");
        StockList stockList = new StockList();
//        try {
//            if (!factor.getOnlyUseTHS()) {
//                stockList = new GrabPaiHang(userID, token).grab();
//            }
//            if(!stockList.getStockList().isEmpty())stockList.setStockList(stockList.getStockList().stream().map(MainSelect::updateStock).filter(Objects::nonNull).collect(Collectors.toList()));
//            if (log.isDebugEnabled())
//                log.debug("是否只用同花顺={}，开盘啦个股数：{}", factor.getOnlyUseTHS(), stockList.getStockList().size());
//        } catch (Exception e) {
//            log.error("抓取开盘啦个股数据异常", e);
//        }
        if (stockList.mergeThs().isEmpty()) {
            log.error("没抓到同花顺数据不出票");
            return new ArrayList<>();
        }
        stockList.setStockList(stockList.getStockList().stream().map(MainSelect::updateStock).filter(Objects::nonNull).collect(Collectors.toList()));
        if (log.isDebugEnabled())
            log.debug("是否只用同花顺={}，合并同花顺后的个股数：{}", factor.getOnlyUseTHS(), stockList.getStockList().size());
        try {
            new TradeAnalyser(stockList.getStockList()).ayalyse();
        } catch (Exception e) {
            log.error("实时卖出信号发生异常", e);
        }
//        ThreadUtil.execute(()->new TradeAnalyser(stockList.getStockList()).ayalyse());

        refreshRate(stockList.getStockList());
//        log.debug(topPlate.toString());
//        log.debug("抓取的排行股票及所属板块:{}", stockList.getStockList().stream().map(stock -> stock.getStock_name() + ":" + stock.getPlate()).collect(Collectors.joining(";")));
        log.info("个股因子筛选...");
        List<Stock> topStock = stockList.top();
        if (log.isDebugEnabled())
            log.debug("叠加因子后选中的股票:{}", topStock.stream().map(s -> s.codeName() + "【" + String.join("；", s.getPlates()) + "】").collect(Collectors.joining(",")));
//        List<String> plateNames = topPlate.stream().map(Plate::getName).collect(Collectors.toList());
//        List<Stock> topPlateStock = topStock.stream().filter(stock -> stock.belongToPlate(plateNames)).collect(Collectors.toList());
        List<Stock> topPlateStock = filterStockInPlate(topStock, topPlate);
        if (!topStock.isEmpty()) {
            log.info("\r\n\n【【【      最强个股      】】】\r\n\n{}\r\n\n", topStock.stream().map(s ->
                    DateUtil.format(s.getGrabTime(), NORM_TIME_FORMATTER) + "\t" + s.codeName() + "\t涨幅:" + s.getZhangfu() + ",净额:" + (s.getZiJinJingE() == null ? "" : NumberChineseFormatter.formatSimple(s.getZiJinJingE().longValue())) + ",净量:" + (s.getZhuLiJingLiang() == null ? "" : NumberUtil.decimalFormat("#.##%", s.getZhuLiJingLiang())) + ",主买:" + (s.getZhuBuyZhanBi() == null ? "" : NumberUtil.decimalFormat("#.##%", s.getZhuBuyZhanBi())) + ",主卖:" + (s.getZhuSellZhanBi() == null ? "" : NumberUtil.decimalFormat("#.##%", s.getZhuSellZhanBi())) + ",排名:" + s.getRenqiRanking() + "\t" + String.join(",", CollectionUtil.intersectionDistinct(topPlate.stream().map(Plate::getName).toList(), s.getPlates()))
            ).collect(Collectors.joining("\r\n")));
        }
        return topPlateStock;
    }

    public List<Stock> filterStockInPlate(List<Stock> stocks, Collection<Plate> plates) {
        plates.stream().filter(p -> !StrUtil.isEmpty(p.getCode())).forEach(plate -> {  //开盘啦查板块里的个股
            try {
                if (!factor.getOnlyUseTHS()) {
                    List<String> ss = new GrabPlateStocks(userID, token).grab(plate.getCode()); //  板块内的股票代码
                    if (ss.isEmpty()) log.info("板块{}({})查询的股票为空", plate.getName(), plate.getCode());
                    ss.stream().map(code -> all_stocks.get(code)).filter(Objects::nonNull).forEach(s -> s.setPlate(plate.getName()));
                }
            } catch (IOException e) {
                log.error("查询开盘啦板块{}中的股票时出错", plate, e);
            }
        });
        Set<Stock> topPlateStock = stocks.stream().filter(stock -> stock.belongToPlate(plates.stream().map(Plate::getName).collect(Collectors.toList()))).collect(Collectors.toSet());
        if (log.isDebugEnabled())
            log.debug("在上榜板块【{}】中的股票有：{}", plates.stream().map(p -> p.getName() + "(" + p.getCode() + ")").collect(Collectors.joining(",")), topPlateStock.stream().map(Stock::codeName).collect(Collectors.joining(",")));
        return new ArrayList<>(topPlateStock);
    }

    private void refreshRate(List<Stock> stocks) {
        goods.values().forEach(gs -> {
            stocks.stream().filter(s -> s.getStock_code().equals(gs.getCode()) && s.getGrabTime() != null && s.getGrabTime().after(DateUtil.parse(gs.getTime(), NORM_DATETIME_PATTERN))).findFirst().ifPresent(s -> {
                gs.setScore(s.getJiage());
                gs.setRate(s.getZhangfu());
                gs.setTime(DateUtil.formatDateTime(s.getGrabTime()));   //当前时间
                gs.setVolume(NumberChineseFormatter.formatSimple(s.getChengJiaoE() == null ? 0 : s.getChengJiaoE().longValue()));
                gs.setZhuBuyZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuBuyZhanBi()));
                gs.setZhuSellZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuSellZhanBi()));
                gs.setZhuLiBuy(NumberChineseFormatter.formatSimple(s.getZiJinBuy() == null ? 0 : s.getZiJinBuy().longValue()));
                gs.setZhuLiSell(NumberChineseFormatter.formatSimple(s.getZiJinSell() == null ? 0 : s.getZiJinSell().longValue()));
                gs.setZhuLiJingE(NumberChineseFormatter.formatSimple(s.getZiJinJingE() == null ? 0 : s.getZiJinJingE().longValue()));
                gs.setZhuLiJingLiang(NumberUtil.decimalFormat("#.##%", s.getZhuLiJingLiang()));
                gs.setShiJiHuanShouLv(s.getShiJiHuanShouLv() + "%");
            });
        });
        List<GoodStock> goodStocks = goods.values().stream().sorted(Comparator.comparing(GoodStock::getUpTime)).collect(Collectors.toList());
        if (!goodStocks.isEmpty()) ThreadUtil.execAsync(new WSNotice(goodStocks, false)::send);
    }

    public Boolean upStock(List<Stock> stocks) throws IOException {
        AtomicReference<Boolean> hasNew = new AtomicReference<>(false);
        stocks.forEach(s -> {
            if (goods.containsKey(s.getStock_code())) {
                GoodStock gs = goods.get(s.getStock_code());
                gs.setScore(s.getJiage());  //当前价格
                gs.setRate(s.getZhangfu()); //当前涨幅
                gs.setTime(DateUtil.formatDateTime(s.getGrabTime()));   //当前时间
                gs.setVolume(NumberChineseFormatter.formatSimple(s.getChengJiaoE().longValue()));
                gs.setZhuBuyZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuBuyZhanBi()));
                gs.setZhuSellZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuSellZhanBi()));
                if (s.getZiJinBuy() != null)
                    gs.setZhuLiBuy(NumberChineseFormatter.formatSimple(s.getZiJinBuy().longValue()));
                if (s.getZiJinSell() != null)
                    gs.setZhuLiSell(NumberChineseFormatter.formatSimple(s.getZiJinSell().longValue()));
                if (s.getZiJinJingE() != null)
                    gs.setZhuLiJingE(NumberChineseFormatter.formatSimple(s.getZiJinJingE().longValue()));
                gs.setZhuLiJingLiang(NumberUtil.decimalFormat("#.##%", s.getZhuLiJingLiang()));
                gs.setShiJiHuanShouLv(s.getShiJiHuanShouLv() + "%");
                if (s.getZhangTingJia() != null) gs.setZhangTingJia(s.getZhangTingJia().toString());
                goods.put(s.getStock_code(), gs);
            } else {
                hasNew.set(true);
                GoodStock gs = new GoodStock();
                gs.setCode(s.getStock_code());
                gs.setName(s.getStock_name());
//                gs.setPlate(s.getShortPlates());
                gs.setPlate(String.join(",", CollectionUtil.intersectionDistinct(s.getPlates(), all_plates.values().stream().filter(Plate::getIsUp).map(Plate::getName).toList())));//取上榜板块交集
                gs.setUpScore(s.getJiage());
                gs.setUpRate(s.getZhangfu());
                gs.setUpTime(DateUtil.formatDateTime(s.getGrabTime()));
                gs.setTime(DateUtil.formatDateTime(s.getGrabTime()));
                gs.setScore(s.getJiage());
                gs.setRate(s.getZhangfu());
                gs.setUpVolume(NumberChineseFormatter.formatSimple(s.getChengJiaoE().longValue()));
                gs.setUpZhuBuyZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuBuyZhanBi()));
                gs.setUpZhuSellZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuSellZhanBi()));
                if (s.getZiJinBuy() != null)
                    gs.setUpZhuLiBuy(NumberChineseFormatter.formatSimple(s.getZiJinBuy().longValue()));
                if (s.getZiJinSell() != null)
                    gs.setUpZhuLiSell(NumberChineseFormatter.formatSimple(s.getZiJinSell().longValue()));
                if (s.getZiJinJingE() != null)
                    gs.setUpZhuLiJingE(NumberChineseFormatter.formatSimple(s.getZiJinJingE().longValue()));
                gs.setUpZhuLiJingLiang(NumberUtil.decimalFormat("#.##%", s.getZhuLiJingLiang()));
                gs.setUpShiJiHuanShouLv(s.getShiJiHuanShouLv() + "%");
                if (s.getChengJiaoE() != null)
                    gs.setVolume(NumberChineseFormatter.formatSimple(s.getChengJiaoE().longValue()));
                gs.setZhuBuyZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuBuyZhanBi()));
                gs.setZhuSellZhanBi(NumberUtil.decimalFormat("#.##%", s.getZhuSellZhanBi()));
                if (s.getZiJinBuy() != null)
                    gs.setZhuLiBuy(NumberChineseFormatter.formatSimple(s.getZiJinBuy().longValue()));
                if (s.getZiJinSell() != null)
                    gs.setZhuLiSell(NumberChineseFormatter.formatSimple(s.getZiJinSell().longValue()));
                if (s.getZiJinJingE() != null)
                    gs.setZhuLiJingE(NumberChineseFormatter.formatSimple(s.getZiJinJingE().longValue()));
                gs.setZhuLiJingLiang(NumberUtil.decimalFormat("#.##%", s.getZhuLiJingLiang()));
                gs.setShiJiHuanShouLv(s.getShiJiHuanShouLv() + "%");
                if (s.getZhangTingJia() != null) gs.setZhangTingJia(s.getZhangTingJia().toString());
                goods.put(s.getStock_code(), gs);
                Boolean buyCount = false;
                try {
                    buyCount = SendBuySignal.buy(gs, s);
                } catch (Exception e) {
                    log.error("发送买入信号异常", e);
                }
                log.info("【上榜】：{}，买入信号{}产生", gs.getCode() + "（" + gs.getName() + "）", (buyCount ? "已" : "未"));
            }
        });
        log.info("\r\n\n【【【      当前榜单      】】】\r\n\n{}\r\n\n", goods.values().stream().map(gs -> gs.getCode() + "\t" + String.format("%-4s", gs.getName()) + "\t" + gs.getTime().substring(11) + "涨幅：" + gs.getRate() + "\t上榜涨幅：" + gs.getUpRate() + "\t上榜时间：" + gs.getUpTime().substring(11) + "\t板块：" + gs.getPlate()).collect(Collectors.joining("\r\n")));
        return hasNew.get();
    }

    private static synchronized void saveGoods(List<GoodStock> goodStocks) {
        File csv = FileUtil.touch(BaseTradePath + System.getProperty("wsn_port", "8888") + "\\goods.csv");
        if (FileUtil.isEmpty(csv)) {
            FileUtil.writeString("股票代码,股票名称,上榜日期,当前时间,当前价格,当前涨幅,当前是否涨停,当前成交额,当前主力净额,当前主力净量,当前主买占比,当前主卖占比,当前主力买,当前主力卖,当前换手率,上榜时间,上榜价格,上榜涨幅,上榜是否涨停,上榜时的成交额,上榜时的主力净额,上榜时的主力净量,上榜时的主买占比,上榜时的主卖占比,上榜时的主力买,上榜时的主力卖,上榜时的换手率,所属板块,\r\n", csv, "GBK");
        }
        CsvData data = CsvUtil.getReader(CsvReadConfig.defaultConfig().setContainsHeader(true)).read(csv, Charset.forName("GBK"));
        List<CsvRow> stored = data.getRows();//.stream().filter(r -> r.getByName("股票代码").equals(gs.getCode()) && r.getByName("上榜日期").equals(gs.getUpTime().substring(0, 10)) /*&& r.getByName("当前时间").compareTo(gs.getTime().substring(11)) > 0*/).collect(Collectors.toList());

        List<String> recodes = goodStocks.stream().filter(gs -> gs.getTime().length() > 16 && gs.getTime().substring(11, 16).compareTo("15:01") >= 0)
                .filter(gs -> stored.stream().filter(r -> r.getByName("股票代码").equals(gs.getCode()) && r.getByName("上榜日期").equals(gs.getUpTime().substring(0, 10)) /*&& r.getByName("当前时间").compareTo(gs.getTime().substring(11)) > 0*/).collect(Collectors.toList()).isEmpty()).map(gs -> {
//            if (!stored.isEmpty()) return "";  //已存当日该股，就不再保存了
                    String recode = gs.getCode().replaceAll(",", "|") + ","
                            + gs.getName().replaceAll(",", "|") + ","
                            + gs.getUpTime().substring(0, 10) + ","                         //上榜日期
                            + gs.getTime().substring(11) + ","                    //当前时间
                            + gs.getScore().replaceAll(",", "|") + ","     //当前价格
                            + gs.getRate().replaceAll(",", "|") + ","       //当前涨幅
                            + gs.isUpLimit(gs.getScore()) + ","                           //当前是否涨停
                            + gs.getVolume().replaceAll(",", "|") + ","//当前成交额
                            + gs.getZhuLiJingE().replaceAll(",", "|") + ","//当前主力净额
                            + gs.getZhuLiJingLiang().replaceAll(",", "|") + ","//当前主力净量
                            + gs.getZhuBuyZhanBi().replaceAll(",", "|") + ","//当前主买占比
                            + gs.getZhuSellZhanBi().replaceAll(",", "|") + ","//当前主卖占比
                            + gs.getZhuLiBuy().replaceAll(",", "|") + ","//当前主力买
                            + gs.getZhuLiSell().replaceAll(",", "|") + ","//当前主力卖
                            + gs.getShiJiHuanShouLv().replaceAll(",", "|") + ","//当前换手率

                            + gs.getUpTime().substring(11) + ","                    //上榜时间
                            + gs.getUpScore().replaceAll(",", "|") + ","//上榜价格
                            + gs.getUpRate().replaceAll(",", "|") + ","//上榜涨幅
                            + gs.isUpLimit(gs.getUpScore()) + ","                           //上榜是否涨停
                            + gs.getUpVolume().replaceAll(",", "|") + ","//上榜时的成交额
                            + gs.getUpZhuLiJingE().replaceAll(",", "|") + ","//上榜时的主力净额
                            + gs.getUpZhuLiJingLiang().replaceAll(",", "|") + ","//上榜时的主力净量
                            + gs.getUpZhuBuyZhanBi().replaceAll(",", "|") + ","//上榜时的主买占比
                            + gs.getUpZhuSellZhanBi().replaceAll(",", "|") + ","//上榜时的主卖占比
                            + gs.getUpZhuLiBuy().replaceAll(",", "|") + ","//上榜时的主力买
                            + gs.getUpZhuLiSell().replaceAll(",", "|") + ","//上榜时的主力卖
                            + gs.getUpShiJiHuanShouLv().replaceAll(",", "|") + ","//上榜时的换手率
                            + gs.getPlate().replaceAll(",", "|") + ",\r\n";//所属板块
                    return recode;
                }).toList();

        if (!recodes.isEmpty()) FileUtil.appendString(String.join("", recodes), csv, "GBK");
    }

    private void keepAlive() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
//                    String json = FileUtil.readString("WenCai.json", "UTF-8");
//                    String token = JsonParser.parseString(json).getAsJsonObject().getAsJsonPrimitive("token").getAsString();
//                    GrabWenCai wencai = new GrabWenCai(token);
//                    String res = wencai.grab("601398涨跌幅");
//                    log.info("现在问财可访问");

//                    new GrabGubit_Login().grab();
//                    new GrabGubit_ClearZiXuan().grab();
//                    List<String> codes = List.of("600266", "603721");
//                    new GrabGubit_AddZiXuan().grab(codes);
//                    List<Stock> stocks = new GrabGubit_ZhangDieTing(codes).grab();
//                    log.info("5日内涨跌停股票：{}", stocks.stream().filter(Stock::existZhangDieTing5Day).map(Stock::getStock_code).collect(Collectors.joining(",")));
                } catch (Exception e) {
//                    log.error(e.getMessage());
//                    try {
//                        new GrabGubit_Login().grab();
//                    } catch (IOException ex) {
//                        log.error(e.getMessage());
//                    }
                }
            }
        }, 100, 1000 * 60 * 5);
    }
}
